﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Code.BLL.Arithmetic
{
    /// <summary>
    /// 处理号码的类
    /// </summary>
    public class ManipulateNumber
    {
        /// <summary>
        /// 按一定的规则，获取可能的注的号码的列表,可对一到五星的号码进行操作
        /// </summary>
        /// <param name="userChoseNumber">用户选择的一种玩法的号码
        /// 格式为：1234,1234,1234,1234,1234
        /// </param>
        /// <returns></returns>
        public static List<string> GetNumList(string userChoseNumber)
        {
            List<string> numList = new List<string>();

            if (userChoseNumber == null || userChoseNumber == "")
                throw new ArgumentException("无效参数");
            if (userChoseNumber.IndexOf(',') < 0)
            {
                foreach (var item in userChoseNumber)
                {
                    numList.Add(item.ToString());
                }
            }
            else
            {
                string[] nums = userChoseNumber.Split(',');
                if (nums.Length > 5)
                    throw new Exception("此方法不能对五星以上的号码进行操作！");
                //递归获取可能的号码
                GetNumber(nums, 0,  "", numList);
            }

            return numList;
        }
        private static void GetNumber(string[] nums, int index, string str,List<string> list)
        {
            if (list == null || list.Count == 0)
            {
                if (index < 0 || index > nums.Length - 1)
                    return;
            }
            for (int i = 0; i < nums[index].Length; i++)
            {
                //取nums数组的index所对应的值的下标为i的号码
                str += nums[index][i].ToString();

                if (index == nums.Length - 1)
                {
                    list.Add(str);
                    str = str.Substring(0, str.Length - 1);//str加入list之后减去最后一个字符
                }
                else
                {
                    GetNumber(nums, ++index,  str,list);//进入下一次取值
                    str = str.Substring(0, str.Length - 1);//取值之后减去最后一个字符
                    index--;//返回上一个nums的值 
                }
            }
        }
        /// <summary>
        /// 复式转为单式(直选)
        /// 如:某用户购买组号码 245789
        /// 转一星的单式为：2,4,5,7,8,9
        /// 转二星的单式为：24,25,27,28,29,45,47,48,49,57,58,59,78,79,89
        /// 转三星的单式为：245,247,248,249,257,258,259,278,279,289,457,458,459,478,479,489,578,579,589,789
        /// 转四星的单式为：2457,2458,2459,2478,2479,2489,2578,2579,2589,2789,4578,4579,4589,4789,5789
        /// 转五星的单式为：24578,24579,24589,24789,25789,45789
        /// 仅对直选有较，复式号码的长度必须>=要转换的单式号码的长度
        /// </summary>
        /// <param name="userChoseNumber">用户选择的复式号码，号码中不能含有9以上的数</param>
        /// <param name="intList">一个整型数组，长度为单式号码的长度(根据数组的长度定义单式号码的长度)</param>
        /// <param name="stringlist">用以保存拆分的单式号码</param>
        public static void GetNumList(string userChoseNumber, int[] intList, List<string> stringlist)
        {
            if (stringlist == null || stringlist.Count == 0)//第一次进入方法时做判断用
            {
                if (userChoseNumber.Length < intList.Length)//如果用户选择的复式号码比将要转换的单式号码短，则视为整型数组参数无较
                    throw new ArgumentException("参数无较！","intList");
                int len = intList.Length;
                intList = new int[len];
                //将整型数组重设为从零开始的数组
                for (int i = 0; i < len; i++)
                {
                    intList[i] = i;
                }
            }

            if (intList[0] == userChoseNumber.Length - intList.Length + 1)//退出当前方法的条件
                return;
            //循环取出每一个下标所对应的号码，然后组合成一个单式号码，数组的最后一位加一，进入下一次循环,直到数组的最后一位的值等于用户选择的号码的长度时退出循环
            for (; intList[intList.Length - 1] < userChoseNumber.Length; intList[intList.Length - 1]++)
            {
                string str = "";
                foreach (var item in intList)
                {
                    str += userChoseNumber.Substring(item, 1);
                }
                stringlist.Add(str);

            }
            //在进入下一次递归时将数组定位到下一次要取的号码的下标所对应的值
            for (int i = intList.Length - 1; i > 0; i--)
            {
                if (intList[i] == userChoseNumber.Length - (intList.Length - 1 - i))
                {
                    intList[i - 1]++;
                    for (int j = i; j < intList.Length; j++)
                        intList[j] = intList[j - 1] + 1;
                }
            }

            GetNumList(userChoseNumber, intList, stringlist);
        }
        /// <summary>
        /// 复式转为单式(直选)
        /// 如:某用户购买组号码 245789
        /// 转一星的单式为：2,4,5,7,8,9
        /// 转二星的单式为：24,25,27,28,29,45,47,48,49,57,58,59,78,79,89
        /// 转三星的单式为：245,247,248,249,257,258,259,278,279,289,457,458,459,478,479,489,578,579,589,789
        /// 转四星的单式为：2457,2458,2459,2478,2479,2489,2578,2579,2589,2789,4578,4579,4589,4789,5789
        /// 转五星的单式为：24578,24579,24589,24789,25789,45789
        /// 仅对直选有较，复式号码的长度必须>=要转换的单式号码的长度
        /// </summary>
        /// <param name="userChoseNumber">用户选择的复式号码,可包含9以上的数字</param>
        /// <param name="intList">一个整型数组，长度为单式号码的长度(根据数组的长度定义单式号码的长度)</param>
        /// <param name="stringlist">用以保存拆分的单式号码</param>
        public static void GetNumList(string[] userChoseNumber, int[] intList, List<string> stringlist)
        {
            if (stringlist == null || stringlist.Count == 0)//第一次进入方法时做判断用
            {
                if (userChoseNumber.Length < intList.Length)//如果用户选择的知复式号码没有将要转换的单式号码长，则视为整型数组参数无较
                    throw new ArgumentException("参数无较");
                int length = intList.Length;
                intList = new int[length];
                //将整型数组重设为从零开始的数组
                for (int i = 0; i < length; i++)
                {
                    intList[i] = i;
                }
            }

            if (intList[0] == userChoseNumber.Length - intList.Length + 1)
                return;
            //循环取出每一个下标所对应的号码，然后组合成一个单式号码，数组的最后一位加一，进入下一次循环,直到数组的最后一位的值等于用户选择的号码的长度时退出循环
            for (; intList[intList.Length - 1] < userChoseNumber.Length; intList[intList.Length - 1]++)
            {
                string str = "";
                foreach (var item in intList)
                {
                    str += userChoseNumber[item];
                }
                stringlist.Add(str);

            }

            //在进入下一次递归时将数组定位到下一次要取的号码的下标所对应的值
            for (int i = intList.Length - 1; i > 0; i--)
            {
                if (intList[i] == userChoseNumber.Length - (intList.Length - 1 - i))
                {
                    intList[i - 1]++;
                    for (int j = i; j < intList.Length; j++)
                        intList[j] = intList[j - 1] + 1;
                }
            }

            GetNumList(userChoseNumber, intList, stringlist);
        }

        /// <summary>
        /// 计算和值的方法，有哪几种可能的组合使得它的和值等于用户选择的和值
        /// </summary>
        /// <param name="userChoseNumber">用户选择的和值号码</param>
        /// <param name="isZhiShuan">是否为直选</param>
        /// <returns></returns>
        public static List<string> GetNumList(string userChoseNumber, bool isZhiShuan)
        {

            int sum = -1;
            if (!int.TryParse(userChoseNumber, out sum))
                throw new ArgumentException("参数格式不正确", "userChoseNumber");
            if (isZhiShuan)
            {
                return GetNumListBySum_ZhiShuan(sum);
            }
            else
            {
                return GetNumListBySum_ZuShuan(sum);
            }
        }

        private static List<string> GetNumListBySum_ZhiShuan(int sum)
        {
            List<string> list = new List<string>();
            for (int i = sum > 18 ? sum - 18 : 0; i < 10; i++)
            {
                if (i > sum)
                    break;
                for (int k = sum - i > 9 ? sum - i - 9 : 0; k < 10; k++)
                {
                    if (sum < k + i)
                        break;
                    list.Add(i + "" + k + (sum - k - i));
                }
            }
            return list;
        }
        private static List<string> GetNumListBySum_ZuShuan(int sum)
        {
            if (sum <= 0 || sum >= 27)
                throw new ArgumentOutOfRangeException("userChoseNumber", "参数大小超出允许范围");
            List<string> list = new List<string>();
            int i = 0;
            int k = 0;
            if (sum > 18)
            {
                i = sum - 18;
            }
            else if (sum > 9)
            {
                int n = sum - 9;
                i = n % 2 == 0 ? n / 2 : (n + 1) / 2;
            }
            else
            {
                if (sum % 2 == 0)
                    k = sum / 2;
                else
                {
                    i = 1;
                    k = (sum - 1) / 2;
                }
            }

            for (; i < 10; i++)
            {
                int num1 = i;
                int num2 = k == 0 ? i : k;
                int num3 = sum - num1 - num2;
                if (num1 == num2 && num1 == num3)
                    continue;
                if (num3 < 0)
                    break;
                list.Add(num1 + "" + num2 + num3);
                k = 0;
            }
            return list;
        }
    }
    
}
